//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_board_dao

import (
	"context"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_board_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

type NodeRefDataDbItem struct {
	RefType     uint32 `bson:"refType"`
	RefTargetId string `bson:"refTargetId"`
}

type NodeTextDataDbItem struct {
	Data string `bson:"data"`
}

type NodeImageDataDbItem struct {
	FileId string `bson:"fileId"`
}

type NodeMermaidDataDbItem struct {
	Data string `bson:"data"`
}

type NodeDbItem struct {
	NodeId          string                 `bson:"_id"`
	BoardId         string                 `bson:"boardId"`
	ProjectId       string                 `bson:"projectId"`
	NodeType        uint32                 `bson:"nodeType"`
	X               int32                  `bson:"x"`
	Y               int32                  `bson:"y"`
	W               uint32                 `bson:"w"`
	H               uint32                 `bson:"h"`
	BgColor         string                 `bson:"bgColor"`
	NodeRefData     *NodeRefDataDbItem     `bson:"nodeRefData"`
	NodeTextData    *NodeTextDataDbItem    `bson:"nodeTextData"`
	NodeImageData   *NodeImageDataDbItem   `bson:"nodeImageData"`
	NodeMermaidData *NodeMermaidDataDbItem `bson:"nodeMermaidData"`
}

func (item *NodeDbItem) ToNode() *project_board_api.Node {
	ret := &project_board_api.Node{
		NodeId:   item.NodeId,
		NodeType: project_board_api.NODE_TYPE(item.NodeType),
		X:        item.X,
		Y:        item.Y,
		W:        item.W,
		H:        item.H,
		BgColor:  item.BgColor,
	}
	if item.NodeType == uint32(project_board_api.NODE_TYPE_NODE_TYPE_REF) {
		ret.NodeData = &project_board_api.Node_NodeRefData{
			NodeRefData: &project_board_api.NodeRefData{
				RefType:     project_board_api.NODE_REF_TYPE(item.NodeRefData.RefType),
				RefTargetId: item.NodeRefData.RefTargetId,
			},
		}
	} else if item.NodeType == uint32(project_board_api.NODE_TYPE_NODE_TYPE_TEXT) {
		ret.NodeData = &project_board_api.Node_NodeTextData{
			NodeTextData: &project_board_api.NodeTextData{
				Data: item.NodeTextData.Data,
			},
		}

	} else if item.NodeType == uint32(project_board_api.NODE_TYPE_NODE_TYPE_IMAGE) {
		ret.NodeData = &project_board_api.Node_NodeImageData{
			NodeImageData: &project_board_api.NodeImageData{
				FileId: item.NodeImageData.FileId,
			},
		}
	} else if item.NodeType == uint32(project_board_api.NODE_TYPE_NODE_TYPE_MERMAID) {
		ret.NodeData = &project_board_api.Node_NodeMermaidData{
			NodeMermaidData: &project_board_api.NodeMermaidData{
				Data: item.NodeMermaidData.Data,
			},
		}
	}
	return ret
}

type _NodeDao struct {
	mc *mongo.Collection
}

func newNodeDao(db *mongo.Database) (*_NodeDao, error) {
	mc := db.Collection(db_ns.DB_NS_PROJECT_BOARD + "node")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"boardId", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_NodeDao{mc: mc}, nil
}

func (db *_NodeDao) Insert(ctx context.Context, dbItem *NodeDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_NodeDao) Exist(ctx context.Context, projectId, boardId, nodeId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId})
	return count > 0, err
}

func (db *_NodeDao) Get(ctx context.Context, projectId, boardId, nodeId string) (*NodeDbItem, error) {
	retItem := &NodeDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId}).Decode(retItem)
	return retItem, err
}

func (db *_NodeDao) Remove(ctx context.Context, projectId, boardId, nodeId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId})
	return err
}

func (db *_NodeDao) RemoveByBoard(ctx context.Context, projectId, boardId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"projectId": projectId, "boardId": boardId})
	return err
}

func (db *_NodeDao) List(ctx context.Context, projectId, boardId string) ([]*NodeDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"projectId": projectId, "boardId": boardId})
	if err != nil {
		return nil, err
	}
	retList := []*NodeDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

// 修复数据用，移除cicd相关节点
func (db *_NodeDao) ListCicd(ctx context.Context) ([]*NodeDbItem, error) {
	// NODE_REF_TYPE_PIPE_LINE = 3;  //CICD(废弃)
	cursor, err := db.mc.Find(ctx, bson.M{"nodeRefData.refType": 3})
	if err != nil {
		return nil, err
	}
	retList := []*NodeDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_NodeDao) UpdatePosition(ctx context.Context, projectId, boardId, nodeId string, x, y int32) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"x": x, "y": y}})
	return err
}

func (db *_NodeDao) UpdateSize(ctx context.Context, projectId, boardId, nodeId string, w, h uint32) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"w": w, "h": h}})
	return err
}

func (db *_NodeDao) UpdateBgColor(ctx context.Context, projectId, boardId, nodeId, bgColor string) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"bgColor": bgColor}})
	return err
}

func (db *_NodeDao) UpdateNodeRefData(ctx context.Context, projectId, boardId, nodeId string, dbItem *NodeRefDataDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"nodeRefData": dbItem}})
	return err
}

func (db *_NodeDao) UpdateNodeTextData(ctx context.Context, projectId, boardId, nodeId string, dbItem *NodeTextDataDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"nodeTextData": dbItem}})
	return err
}

func (db *_NodeDao) UpdateNodeImageData(ctx context.Context, projectId, boardId, nodeId string, dbItem *NodeImageDataDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"nodeImageData": dbItem}})
	return err
}

func (db *_NodeDao) UpdateNodeMermaidData(ctx context.Context, projectId, boardId, nodeId string, dbItem *NodeMermaidDataDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"projectId": projectId, "boardId": boardId, "_id": nodeId},
		bson.M{"$set": bson.M{"nodeMermaidData": dbItem}})
	return err
}
